package pl.klangner.recobox.classifier
{
  import flash.display.Graphics;
  import flash.geom.Point;
  
  import pl.klangner.recobox.geometry.Rect;
  import pl.klangner.recobox.geometry.Vector;
  import pl.klangner.recobox.geometry.algorithms.DPPolylineSimplification;
  
	
	/**
	 * Curve considit of sets of points 
	 */
	public class InkMultiStroke
	{
	  // --------------------------------------------------------------------------------------------
		public function InkMultiStroke(ps:Array = null){
			
			_strokes = new Array();
			
			if(ps != null){
				_strokes.push(ps);
		 	}else{
				_strokes.push(new Array());
		 	}

		}
		
	  // --------------------------------------------------------------------------------------------
	  /**
	  * After adding point, clear cache with simplified points
	  */
		public function addPoint(p:Point):void{
			_strokes[_strokes.length-1].push(p);
		  _simplifiedPoints = null;
		}

	  // --------------------------------------------------------------------------------------------
	  /**
	  * Move mouse to new point (mouse is up)
	  */
		public function addStroke():void{
			// Don't add new stroke if current one is empty 
			if(_strokes[_strokes.length-1].length > 0)
				_strokes.push(new Array());
		}

	  // --------------------------------------------------------------------------------------------
		public function get boundingBox():Rect {
			
			var stroke:Array = _strokes[0];
			if(_box == null){
				for each( var point:Point in stroke){
					if(_box == null){
						_box = new Rect(point.x, point.y);
					}
					else{
						if(point.x < _box.left)
							_box.left = point.x;
						else if(point.x > _box.right)
							_box.right = point.x;
	
						if(point.y < _box.top)
							_box.top = point.y;
						else if(point.y > _box.bottom)
							_box.bottom = point.y;
					}
				}
				
				// no points
				if(_box == null){
					_box = new Rect(0, 0);
				}
			}
			
			return _box;	
		}

	  // --------------------------------------------------------------------------------------------
		public function draw(g:Graphics):void{

			var stroke:Array = _strokes[0];
			if(stroke.length > 0){
	    	g.moveTo(stroke[0].x, stroke[0].y);
	    	for(var i:int = 1; i < stroke.length; i++) {
	    		g.lineTo(stroke[i].x, stroke[i].y);
	    	}
	  	}
		}
		
	  // --------------------------------------------------------------------------------------------
		public function drawSimplyfied(g:Graphics):void{

			var sp:Array = simplifiedPoints;
			if(sp.length > 0){
	    	g.moveTo(sp[0].x, sp[0].y);
	    	for(var i:int = 1; i < sp.length; i++) {
	    		g.lineTo(sp[i].x, sp[i].y);
	    	}
	  	}
		}
		
	  // --------------------------------------------------------------------------------------------
	  /**
	  * Length can be precalculated
	  */
		public function get length():Number{
		
			if(_length < 0){
	      var v:Vector;
	
				_length = 0;
	    	for(var i:int = 1; i < _strokes[0].length; i++) {
	    	  v = Vector.points2Vector(_strokes[0][i], _strokes[0][i-1]);
	    		_length += v.length;
	    	}
			}
			
			return _length;
		}
		
		// --------------------------------------------------------------------------------------------
		/**
		 * @return true if there are any points.
		 */
		public function loadFromString(data:String):void{
			
			if(data != null){
				var groups:Array = data.split(";");
				for each(var group:String in groups){
					var points:Array = group.match(/[\d\.]+/g);

					addStroke();				
	      	for(var i:int = 1; i < points.length; i += 2){
	      		addPoint(new Point(points[i-1], points[i]));
	      	}
	     	}
	  	}
	  	
		}
		
		
	  // --------------------------------------------------------------------------------------------
	  /** Get points after segmentation */
		public function get simplifiedPoints():Array {
			
			if(_simplifiedPoints == null){
				
				var dp:DPPolylineSimplification = new DPPolylineSimplification();
				_simplifiedPoints = new Array();
				
				dp.tolerance = PRECISION * boundingBox.diagonalLength;
				_simplifiedPoints = new Array();
				for each(var stroke:Array in _strokes){
					_simplifiedPoints = _simplifiedPoints.concat(dp.simplify(stroke));
				}
			}
			
			return _simplifiedPoints;
		}
		
	  // --------------------------------------------------------------------------------------------
		public function toString():String{
			var text:String = new String();
			
			for each(var stroke:Array in _strokes){
				if(text.length > 0)
					text += "; ";
					 					
				for(var i:int = 0; i < stroke.length; i++){
					if(i > 0)
						text += ", "; 					
					text += "(" + stroke[i].x + "," + stroke[i].y + ")";
				}
			}
			
			return text;
		}

 	  // --------------------------------------------------------------------------------------------
    // Private members
    /** Array with strokes. Strokes are array of points */
    private var _strokes:Array;
    private var _simplifiedPoints:Array = null;
    private var _length:Number = -1;
    private var _box:Rect;
    		
    private static var PRECISION:Number = 0.1;
	}
}